/********************************************************
 Name          : pcc.c
 Author        : Khachatur Gyozalyan
 Copyright     : Copyright by Antel Systems
 Description   :
 **********************************************************/
// Include Files
#include "pcc/pcc.h"
#include "string.h"

unsigned char gPCC_PacketID = 0;
/*
void pcc_interleave(unsigned char *buffer, unsigned int length)
{
	unsigned char Block[PCC_BLOCK_SIZE];
	unsigned char *pPtr;
	unsigned char *pBlockPtr;
	int i,j,k, byte,bit;
	unsigned int number_of_blocks = length / 20;

	for (i = 0 ; i < number_of_blocks ; i++)
	{
		memset(Block,0,sizeof(Block));
		pPtr = Block;
		bit = 7;
		byte = 0;
		pBlockPtr = buffer + (i * PCC_BLOCK_SIZE);
		for (j = 0 ; j < PCC_BLOCK_SIZE ; j++)
		{
			for (k = 7 ; k >= 0 ; k--)
			{
				*pPtr |= (((pBlockPtr[byte] >> bit) & 0x01) << k);
				byte++;
				if(byte == PCC_BLOCK_SIZE)
				{
					byte = 0;
					bit--;
				}
			}
			pPtr++;
		}
		memcpy(buffer + (i * PCC_BLOCK_SIZE),Block,PCC_BLOCK_SIZE);
	}
}*/

void pcc_interleave(unsigned char * data,int p_iNumberOfBlocks)
{
  unsigned char v_Block[PCC_BLOCK_SIZE]; // triplet
  unsigned char *v_pPtr = v_Block;
  unsigned char *v_pBlockPtr;
  int byte,bit;
  int v_ii,v_jj,v_kk;

  for (v_ii = 0; v_ii < p_iNumberOfBlocks;v_ii++)
  {
    memset(v_Block,0,sizeof(v_Block));
    v_pPtr = v_Block;
    bit = 7;
    byte = 0;
	v_pBlockPtr = &data[v_ii * PCC_BLOCK_SIZE];
    for (v_jj = 0; v_jj < PCC_BLOCK_SIZE;v_jj++)
    {
    	for (v_kk = 7 ; v_kk >= 0 ; v_kk--)
    	{
    		*v_pPtr |= (((v_pBlockPtr[byte] >> bit) & 0x01) << v_kk);
    		byte++;
    		if(byte == PCC_BLOCK_SIZE)
    		{
    			byte = 0;
    			bit--;
    		}
    	}
		v_pPtr++;
    }
    memcpy(&data[v_ii * PCC_BLOCK_SIZE],v_Block,PCC_BLOCK_SIZE);
  }
}


void pcc_deinterleave(unsigned char *buffer, unsigned int length)
{
	unsigned char Block[PCC_BLOCK_SIZE];
	unsigned char *pBlockPtr;
	int i,j,k, byte,bit;
	unsigned int number_of_blocks = length / 20;

	for (i = 0 ; i < number_of_blocks ; i++)
	{
		memset(Block,0,sizeof(Block));
		bit = 7;
		byte = 0;
		pBlockPtr = buffer + (i * PCC_BLOCK_SIZE);
		for (j = 0 ; j < PCC_BLOCK_SIZE ; j++)
		{
			for (k = 7 ; k >= 0 ; k--)
			{
				Block[byte] |= (((pBlockPtr[j] >> k) & 0x01) << bit);
				byte++;
				if(byte == PCC_BLOCK_SIZE)
				{
					byte = 0;
					bit--;
				}
			}
		}
		memcpy(buffer + (i * PCC_BLOCK_SIZE),Block,PCC_BLOCK_SIZE);
	}
}

unsigned short PCC_CRC16(const unsigned char *p_pBuffer,int p_Size)
{
  int v_CRC, v_Index;

  v_CRC = 0;
  while(--p_Size >= 0)
  {
    v_CRC = v_CRC ^ (int)*p_pBuffer++ << 8;
    for(v_Index = 0; v_Index < 8; ++v_Index)
    {
      if(v_CRC & 0x8000)
        v_CRC = v_CRC << 1 ^ 0x1021;
      else
        v_CRC = v_CRC << 1;
    }
  }
  return (unsigned short)(v_CRC & 0xFFFF);
}

unsigned int pcc_create_packet(unsigned char *in_buffer,unsigned char *out_buffer, unsigned int length)
{
	unsigned int frame_size,block_count,temp_length = length,index,in_buffer_index = 0;
	struct pcc_header *Pcc_Header;
	unsigned short crc_16;

	if(length > 4096)
		return 0;

	if(length <= 13)
	{
		block_count = 1;
	}
	else
	{
		block_count = ((length - 13) / 18) + 1;
		if(((length - 13) % 18))
			block_count++;
	}
	frame_size = block_count * PCC_BLOCK_SIZE;
	memset(out_buffer,0x00,frame_size);

	Pcc_Header = (struct pcc_header *)out_buffer;
	Pcc_Header->byte_FF = 0xFF;
	Pcc_Header->byte_00 = 0x00;
	Pcc_Header->Packet_ID = gPCC_PacketID;
	Pcc_Header->Data_bytes_number_high = (length >> 8) & 0xFF;
	Pcc_Header->Data_bytes_number_low = (length >> 0) & 0xFF;

	if(temp_length <= 13)
	{
		memcpy(out_buffer + 5,in_buffer,temp_length);
		in_buffer_index += temp_length;
		temp_length = 0;
	}
	else
	{
		memcpy(out_buffer + 5,in_buffer,13);
		in_buffer_index += 13;
		temp_length -= 13;
	}
	crc_16 = PCC_CRC16(out_buffer,18);
	out_buffer[18] = (crc_16 >> 8) & 0xFF;
	out_buffer[19] = (crc_16 >> 0) & 0xFF;
	index = 20;

	block_count--;

	while(block_count)
	{
		if(temp_length <= 18)
		{
			memcpy(out_buffer + index,in_buffer + in_buffer_index,temp_length);
			in_buffer_index += temp_length;
			temp_length = 0;
		}
		else
		{
			memcpy(out_buffer + index,in_buffer + in_buffer_index,18);
			in_buffer_index += 18;
			temp_length -= 18;
		}

		crc_16 = PCC_CRC16(out_buffer + index,18);
		out_buffer[index + 18] = (crc_16 >> 8) & 0xFF;
		out_buffer[index + 19] = (crc_16 >> 0) & 0xFF;

		index += PCC_BLOCK_SIZE;
		block_count--;
	}

	pcc_interleave(out_buffer, frame_size/20);

	gPCC_PacketID++;

	return frame_size;
}


